package com.lzhl.buildjar.ui.support;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

/**
 * 下拉选择控件
 * @author 李柱良(@柱子的日月)
 * @date 2015/11/25
 */
public class JFileField extends JTextField implements KeyListener {
    private JPopupMenu popupMenu = null;
    private DefaultListModel suggestModel = null;
    private JList suggestList = null;

    private SuggestProvider provider = null;

    public JFileField() {
        jbinit ();
        init();
    }
    public JFileField(SuggestProvider provider) {
        this();
        this.provider = provider;
    }
    private void jbinit() {
        popupMenu = new JPopupMenu();
        popupMenu.setLayout(new BorderLayout(0, 2));

        suggestModel = new DefaultListModel();
        suggestList = new JList ();
        suggestList.setFocusable(false);
        suggestList. setFont (new Font ("宋体", Font. PLAIN, 12));
        suggestList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        suggestList.setModel(suggestModel);

        JScrollPane scrollPane = new JScrollPane(suggestList);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        popupMenu.add(scrollPane, BorderLayout.CENTER);
    }
    private void init() {
        addKeyListener(this);

        suggestList.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if(e.getClickCount() == 2) {
                    Object value = suggestList.getSelectedValue();
                    popupMenu.setVisible(false);
                    if(value != null) {
                        setText(value.toString());
                    }
                }
            }
        });

        setBorder(new FillBorder());
        addFocusListener(new FocusAdapter() {
            public void focusLost(FocusEvent e) {
                putClientProperty("hasError", null);
                repaint();
            }
        });
    }

    public SuggestProvider getProvider() {
        return provider;
    }

    public void setProvider(SuggestProvider provider) {
        this.provider = provider;
    }

    private boolean isControlKey(int code) {
        return code == KeyEvent.VK_DOWN || code == KeyEvent.VK_RIGHT
                || code == KeyEvent.VK_UP || code == KeyEvent.VK_LEFT
                || code == KeyEvent.VK_ESCAPE || code == KeyEvent.VK_CAPS_LOCK
                || code == KeyEvent.VK_CONTROL || code == KeyEvent.VK_ALT
                || code == KeyEvent.VK_SHIFT || code == KeyEvent.VK_ENTER
                || code == KeyEvent.VK_TAB || (code >= KeyEvent.VK_F1 && code <= KeyEvent.VK_F12);
    }

    public void keyReleased(KeyEvent e) {
        if (e.getSource() == this && !isControlKey(e.getKeyCode())) {
            if (e.isAltDown() || e.isControlDown()) {
                return;
            }
            showSuggests();
        }
        //在dialog中不会自动关闭
        else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
            popupMenu.setVisible(false);
        }
    }
    public void keyPressed(KeyEvent e) {
        if (!popupMenu.isVisible()) {
            return;
        }

        if (e.getKeyCode() == KeyEvent.VK_DOWN) {
            if (!suggestList.hasFocus()) {
                if (suggestList.getSelectedIndex() == suggestList.getModel().getSize() - 1) {
                    suggestList.setSelectedIndex(0);
                }
                else {
                    suggestList.setSelectedIndex(suggestList.getSelectedIndex() + 1);
                }
            }
            suggestList.ensureIndexIsVisible(suggestList.getSelectedIndex());
        }
        else if (e.getKeyCode() == KeyEvent.VK_UP) {
            if (!suggestList.hasFocus()) {
                if (suggestList.getSelectedIndex() == 0) {
                    suggestList.setSelectedIndex(suggestList.getModel().getSize() - 1);
                }
                else {
                    suggestList.setSelectedIndex(suggestList.getSelectedIndex() - 1);
                }
            }
            suggestList.ensureIndexIsVisible(suggestList.getSelectedIndex());
        }
        else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
            Object value = suggestList.getSelectedValue();
            popupMenu.setVisible(false);
            if (value != null) {
                setText(value.toString());
            }
        }
    }

    public void keyTyped(KeyEvent e) {
    }

    private void showSuggests() {
        popupMenu.setVisible(false);
        suggestModel.removeAllElements();

        String text = getText();
        java.util.List<String> suggests = suggest(text);
        if (suggests.size() <= 0) {
            return;
        }
        for (String suggest : suggests) {
            suggestModel.addElement(suggest);
        }

        suggestList.setSelectedIndex(0);
        suggestList.ensureIndexIsVisible(0);

        int count = suggests.size();
        if (count < 4) {
            count = 4;
        } else if (count > 24) {
            count = 24;
        }
        popupMenu.setSize(getWidth(), count * 18);
        popupMenu.setPreferredSize(new Dimension(getWidth(), count * 18));
        popupMenu.show(this, 0, getHeight() + 1);
        requestFocus();
    }

    public java.util.List<String> suggest(String text) {
        java.util.List<String> suggests = null;

        if(provider != null) {
            suggests = provider.suggest(text);
        }
        if(suggests == null) {
            suggests = new ArrayList<String>();
        }

        return suggests;
    }

    public boolean isSuggesting() {
        return popupMenu.isVisible();
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        Container con = frame.getContentPane();
        con.setLayout(new BorderLayout());

        JFileField fileField = new JFileField(new FileProvider(true));
        fileField.setMinimumSize(new Dimension(400, 200));
        fileField.setMaximumSize(new Dimension(400, 200));
        con.add(fileField, BorderLayout.CENTER);

        frame.setSize(400, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
